/*
 * NIST Healthcare Test Framework
 * SoapClient.java Jul 29, 2010
 *
 * This code was produced by the National Institute of Standards and
 * Technology (NIST). See the "nist.disclaimer" file given in the distribution
 * for information on the use and redistribution of this software.
 */
package gov.nist.healthcare.testframework.communication.soap.client;

import gov.nist.healthcare.core.MalformedMessageException;
import gov.nist.healthcare.core.message.HL7Message;
import gov.nist.healthcare.core.message.v3.HL7V3Message;
import gov.nist.healthcare.testframework.communication.HSV3Request;
import gov.nist.healthcare.testframework.communication.HSV3Response;
import gov.nist.healthcare.testframework.communication.WSAException;
import gov.nist.healthcare.testframework.communication.client.ClientThread;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.UUID;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.SOAPException;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.impl.DefaultHttpClientConnection;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.params.BasicHttpParams;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlException;
import org.xml.sax.SAXException;

/**
 * This class is a SOAP client.
 * 
 * @author Sydney Henrard (NIST)
 * @author Michael Ogata
 */
public class SoapClient extends ClientThread {

    private static final Logger logger = Logger.getLogger(ClientThread.class.getName());
    private HSV3Request current_request;
    private HSV3Response current_response;
    private final String ACTION_PREFIX = "urn:hl7-org:v3";

    // private static final String WSA_FROM =
    // "http://pixpdq2010tests.nist.gov:8080/";
    private static String DEFAULT_ENDPOINT_REFERENCE = "http://www.w3.org/2005/08/addressing/anonymous";

    /**
     * Constructor
     * 
     * @param secure
     */
    public SoapClient(boolean secure) {
        this.secure = secure;
    }

    @Override
    public HL7Message getMessage() {

        HL7Message extracted_message = null;

        try {
            HSV3Response current_response;
            BasicHttpParams params = new BasicHttpParams();
            DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
            conn.bind(socket, params);
            HttpResponse response;

            response = conn.receiveResponseHeader();
            // Check HTTP Protocol version
            if (!(response.getProtocolVersion().equals(
                    org.apache.http.HttpVersion.HTTP_1_1) || response.getProtocolVersion().equals(
                    org.apache.http.HttpVersion.HTTP_1_0))) {
                logger.debug("According to WS Basic Progile 1.1, R1141: A"
                        + " MESSAGE MUST be sent using either HTTP/1.1 or HTTP/1.0.\n"
                        + "Version detected: " + response.getProtocolVersion());
            }

            conn.receiveResponseEntity(response);

            current_response = new HSV3Response((BasicHttpResponse) response);

            try {
                logger.debug("Recieved Response: \n"
                        + current_response.getStringRepresentation());
            } catch (SAXException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ParserConfigurationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            // Check for WSA
            try {
                if (current_response.isWSAValid()) {
                    logger.debug("WSA Header Correct");
                }
            } catch (WSAException wse) {
                logger.debug(wse.getMessage());
            }
            extracted_message = current_response.getV3payload();
        } catch (HttpException http) {
            logger.debug("Exception when reading the HTTP connection", http);
        } catch (SOAPException soap) {
            logger.debug("Exception when parsing the SOAP message", soap);
        } catch (XmlException xml) {
            logger.debug("Exception when creating the HL7V3 message", xml);
        } catch (MalformedMessageException mme) {
            logger.debug("Exception when creating the HL7V3 message", mme);
        } catch (IOException ioe) {
            logger.debug("Exception when reading the input stream", ioe);
        }
        return extracted_message;
    }

    @Override
    public String encode(HL7Message message) {
        return encode(message, "/");
    }

    @Override
    public String encode(HL7Message message, String endpoint) {
        String encoded_message = "";
        String interactionid = "";

        try {
            current_request = new HSV3Request((HL7V3Message) message, endpoint);
            InetSocketAddress from = (InetSocketAddress) socket.getLocalSocketAddress();
            InetSocketAddress to = (InetSocketAddress) socket.getRemoteSocketAddress();
            // Build WSA Header values
            interactionid = ((HL7V3Message) message).getInteractionId();
            String wsaTo = String.format("http://%s:%d%s",
                    to.getAddress().getHostAddress(), to.getPort(), endpoint);
            String wsaAction = wsaAction = ACTION_PREFIX + ":" + interactionid;

            // Check if this is a QUQI_IN000002UV01 for Jun
            if (interactionid.equals("QUQI_IN000003UV01")) {
                String continuationQuantity = ((HL7V3Message) message).getValue("declare namespace v3=\'urn:hl7-org:v3\' /*/v3:controlActProcess/v3:queryContinuation/v3:continuationQuantity/@value");
                String statusCode = ((HL7V3Message) message).getValue("declare namespace v3=\'urn:hl7-org:v3\' /*/v3:controlActProcess/v3:queryContinuation/v3:statusCode/@code");

                if ((continuationQuantity != null)
                        && (continuationQuantity.equals("0") && statusCode.equals("aborted"))) {
                    wsaAction += "_Cancel";
                } else {
                    wsaAction += "_Continue";
                }
            }
            String messageid = "urn:uuid:" + UUID.randomUUID();
            // Set WSA Header Values
            current_request.setWSATo(wsaTo);
            current_request.setWSAAction(wsaAction);
            current_request.setWSAReplyTo(DEFAULT_ENDPOINT_REFERENCE);
            current_request.setWSAMessageID(messageid);

            encoded_message = current_request.getStringRepresentation();
        } catch (SOAPException e) {
            logger.debug("Error parsing HL7V3Message into a SOAP object: \n"
                    + e.getMessage());

        } catch (IOException e) {
            logger.debug("IOException: " + e);
        } catch (SAXException e) {
            logger.debug("Error parsing the XML in the HL7V3Message: \n"
                    + e.getMessage());
        } catch (ParserConfigurationException e) {
            logger.debug("ParserConfigurationException " + e);
        }
        return encoded_message;

    }
}
